﻿using System;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using IndicoInterface;
using IndicoInterface.SimpleAgendaDataModel;
using DTBuilderLib;
using System.IO;

namespace t_DTBuilderLib
{
    /// <summary>
    /// Summary description for t_JPEGRender
    /// </summary>
    [TestClass]
    public class t_JPEGRender
    {
        public t_JPEGRender()
        {
            //
            // TODO: Add constructor logic here
            //
        }

        private TestContext testContextInstance;

        /// <summary>
        ///Gets or sets the test context which provides
        ///information about and functionality for the current test run.
        ///</summary>
        public TestContext TestContext
        {
            get
            {
                return testContextInstance;
            }
            set
            {
                testContextInstance = value;
            }
        }

        #region Additional test attributes
        //
        // You can use the following additional attributes as you write your tests:
        //
        // Use ClassInitialize to run code before running the first test in the class
        // [ClassInitialize()]
        // public static void MyClassInitialize(TestContext testContext) { }
        //
        // Use ClassCleanup to run code after all tests in a class have run
        // [ClassCleanup()]
        // public static void MyClassCleanup() { }
        //
        // Use TestInitialize to run code before running each test 
        // [TestInitialize()]
        // public void MyTestInitialize() { }
        //
        // Use TestCleanup to run code after each test has run
        // [TestCleanup()]
        // public void MyTestCleanup() { }
        //
        #endregion

        [TestMethod]
        public void JPEGRenderConstructor()
        {
            JPEGRender r = new JPEGRender();

            Assert.IsTrue(r.DotsPerInch == 600, "DPI not set correctly");
        }

#if false
        /// This is now a password protected meeting.
        [TestMethod]
        public void RenderMeetingTalkByTalk()
        {
            /// Render a small meeting that we have downloaded.
            JobDownloader jd = new JobDownloader();
            AgendaInfo a = new AgendaInfo(33078);

            Meeting finalMeeting = null;

            jd.StartMeetingDownload(a.GetNormalizedConferenceData(),
                (m, s, t, p) => { },
                (m) => { finalMeeting = m; });

            while (finalMeeting == null)
            {
                System.Threading.Thread.Sleep(100);
            }

            ///
            /// Now do the render itself.
            /// 

            var talks = from s in finalMeeting.Sessions
                        from t in s.Talks
                        where t.SlideURL != null
                        where t.SlideURL.Length != 0
                        select t;

            JPEGRender r = new JPEGRender();
            foreach (var talk in talks)
            {
                List<FileInfo> output_jpegs = null;
                output_jpegs = r.RenderTalk(talk.SlideURL);

                /// Next, make sure every single resultant file exists.
                if (output_jpegs != null)
                {
                    Assert.IsTrue(output_jpegs.FindAll(x => !x.Exists).Count == 0, "Found some jpegs that aren't actually there!");

                    /// Make sure the render token exists.
                    string talkloc = talk.SlideURL.Substring(0, talk.SlideURL.Length - 4);
                    Assert.IsTrue(System.IO.File.Exists(talkloc + "-done.txt") || talk.ID == "4", "Done token file does not exist!");
                }
            }
            
        }

#if false
        /// This is now a password protected meeting.
        [TestMethod]
        public void RenderMeetingAllAtOnce()
        {
            /// Render a small meeting that we have downloaded.
            JobDownloader jd = new JobDownloader();
            AgendaInfo a = new AgendaInfo(33078);
            var data = jd.DownloadMeeting(a.GetNormalizedConferenceData());

            ///
            /// Now do the render itself.
            /// 


            JPEGRender r = new JPEGRender();
            var results = r.RenderMeeting(data);

            var talks = from s in data.Sessions
                        from t in s.Talks
                        where t.SlideURL != null
                        where t.SlideURL.Length != 0
                        select t;
            foreach (var talk in talks)
            {
                /// Do the talks exist in the list?
                Assert.IsTrue(results.ContainsKey(talk), "Talk info is not in the collection!");
            }
        }
#endif
#endif

        [TestMethod]
        public void RenderSinglePSTalk()
        {
            RenderASinglePSTalk(TalkFromLocalFile("..\\..\\..\\t_DTBuilderLib\\normalPSprinting.ps"), 6);
        }

        [TestMethod]
        public void RenderSinglePSTalk2()
        {
            /// This is a 12 meg file found at: http://indico.cern.ch/materialDisplay.py?contribId=s1t14&materialId=0&confId=a042880
            /// We currently don't have the ability to tell that this talk is oriented "correctly" -- there is nothing in it that tells us.
            /// However, Adobe seems to get it right. See the bug on codeplex.
            RenderASinglePSTalk(TalkFromLocalFile("..\\..\\..\\t_DTBuilderLib\\normalPSprinting2.ps"), 46);
        }

        private static void RenderASinglePSTalk(Talk t, int nslides)
        {
            /// There is a ".PS" file that needs to be rendered. Lets try it out.
            /// 

            Meeting m = MeetingFromSingleTalk(t);

            JPEGRender r = new JPEGRender();
            var renderedslides = r.RenderMeeting(m);
            Assert.IsTrue(renderedslides.ContainsKey(t), "Rendered slides does not contain slides for the post script guy!");
            var slides = renderedslides[t];

            Assert.IsTrue(slides.Count == nslides, "Wrong number of slides in the rendering");

            int[] sizes = TestUtilities.GetImageSize(slides[0]);
            Assert.IsTrue(sizes[0] == r.DotsPerInch * 11, "Number of pixels along X is wrong");
            Assert.IsTrue(sizes[1] == ((float)r.DotsPerInch * 8.5), "Number of pixels along Y is wrong");
        }

        [TestMethod]
        public void RenderSingleRotatedPSTalk()
        {
            /// There is a ".PS" file that needs to be rendered (and rotated!!). Lets try it out.
            /// 
            Talk t = TalkFromLocalFile("..\\..\\..\\t_DTBuilderLib\\rotatedpsfile.ps");

            Meeting m = MeetingFromSingleTalk(t);

            JPEGRender r = new JPEGRender();
            var renderedslides = r.RenderMeeting(m);
            Assert.IsTrue(renderedslides.ContainsKey(t), "Rendered slides does not contain slides for the post script guy!");
            var slides = renderedslides[t];
            Assert.IsTrue(slides.Count == 22, "Wrong number of slides in the rendering");

            int[] sizes = TestUtilities.GetImageSize(slides[0]);
            Assert.IsTrue(sizes[0] == r.DotsPerInch * 11, "Number of pixels along X is wrong");
            Assert.IsTrue(sizes[1] == ((float)r.DotsPerInch * 8.5), "Number of pixels along Y is wrong");
        }

        [TestMethod]
        public void RenderSinglePDFTalk()
        {
            /// There is a ".PDF" file that needs to be rendered. Lets try it out.
            /// 
            Talk t = TalkFromLocalFile("..\\..\\..\\t_DTBuilderLib\\regularPDFfile.pdf");

            Meeting m = MeetingFromSingleTalk(t);

            JPEGRender r = new JPEGRender();
            var renderedslides = r.RenderMeeting(m);
            Assert.IsTrue(renderedslides.ContainsKey(t), "Rendered slides does not contain slides for the post script guy!");
            var slides = renderedslides[t];
            Assert.IsTrue(slides.Count == 6, "Wrong number of slides in the rendering");

            int[] sizes = TestUtilities.GetImageSize(slides[0]);
            Assert.IsTrue(sizes[0] == r.DotsPerInch * 11, "Number of pixels along X is wrong");
            Assert.IsTrue(sizes[1] == ((float)r.DotsPerInch * 8.5), "Number of pixels along Y is wrong");
        }

        [TestMethod]
        public void RenderWhitePDFTalk()
        {
            /// There is a ".PDF" file that needs to be rendered. Lets try it out.
            /// 
            /// Ghost script has real problems with this talk, though acroread has no trouble. But, basically, it
            /// seems to render with a huge amount of whitespace around the talk. No clue why - looks like it was
            /// made by acro distiller...??
            /// 

            Talk t = TalkFromLocalFile("..\\..\\..\\t_DTBuilderLib\\PDFWithWhiteSpace.pdf");

            Meeting m = MeetingFromSingleTalk(t);

            JPEGRender r = new JPEGRender();
            var renderedslides = r.RenderMeeting(m);
            Assert.IsTrue(renderedslides.ContainsKey(t), "Rendered slides does not contain slides for the post script guy!");
            var slides = renderedslides[t];
            Assert.IsTrue(slides.Count == 9, "Wrong number of slides in the rendering");

            int[] sizes = TestUtilities.GetImageSize(slides[0]);
            Assert.IsTrue(sizes[0] == r.DotsPerInch * 11, "Number of pixels along X is wrong");
            Assert.IsTrue(sizes[1] == ((float)r.DotsPerInch * 8.5), "Number of pixels along Y is wrong");
        }

        [TestMethod]
        public void RenderSinglePPTTalk()
        {
            RenderSingleTalkWithChecks(TalkFromLocalFile("..\\..\\..\\t_DTBuilderLib\\regularPPTfile.PPT"), 6);
        }

        [TestMethod]
        public void RenderSinglePPTTalk2()
        {
            RenderSingleTalkWithChecks(TalkFromLocalFile("..\\..\\..\\t_DTBuilderLib\\regularPPTfile2.ppt"), 19);
        }

        private static void RenderSingleTalkWithChecks(Talk t, int nslides)
        {
            Meeting m = MeetingFromSingleTalk(t);

            JPEGRender r = new JPEGRender();
            var renderedslides = r.RenderMeeting(m);
            Assert.IsTrue(renderedslides.ContainsKey(t), "Rendered slides does not contain slides for the post script guy!");
            var slides = renderedslides[t];
            Assert.IsTrue(slides.Count == nslides, "Wrong number of slides in the rendering");

            int[] sizes = TestUtilities.GetImageSize(slides[0]);
            Assert.IsTrue(sizes[0] == r.DotsPerInch * 10, "Number of pixels along X is wrong");
            Assert.IsTrue(sizes[1] == ((float)r.DotsPerInch * 7.5), "Number of pixels along Y is wrong");
        }

        [TestMethod]
        public void RenderDoublePPTTalk()
        {
            Talk t1 = TalkFromLocalFile("..\\..\\..\\t_DTBuilderLib\\regularPPTfile.PPT");
            Talk t2 = TalkFromLocalFile("..\\..\\..\\t_DTBuilderLib\\regularPPTfile.PPT", "Dup-");

            Meeting m = MeetingFromTalks(new Talk[] { t1, t2 });

            JPEGRender r = new JPEGRender();
            var renderedslides = r.RenderMeeting(m);

            Assert.IsTrue(renderedslides.Count == 2, "Wrong number of talks came back!");
            Assert.IsTrue(renderedslides.ContainsKey(t1), "Rendered slides does not contain slides for the t1 guy!");
            Assert.IsTrue(renderedslides.ContainsKey(t2), "Rendered slides does not contain slides for the t2 guy!");

            Assert.IsTrue(renderedslides[t1].Count == renderedslides[t2].Count, "Number of rendered slides is not same in each talk");
            Assert.IsTrue(renderedslides[t1].Count == 6, "Wrong number of rendered slides in t1!");
        }

        [TestMethod]
        public void RenderBadTalk()
        {
            /// Make sure we explode if we try to render a file type that is not allowed.
            Talk t = TalkFromLocalFile("..\\..\\..\\t_DTBuilderLib\\bogusFile.txt");

            Meeting m = MeetingFromSingleTalk(t);

            FileInfo log = new FileInfo("log.txt");
            if (log.Exists)
            {
                log.Delete();
            }
            try
            {
                Utilities.Logger.UseFileLogger(log);
                JPEGRender r = new JPEGRender();
                var renderedslides = r.RenderMeeting(m);
                Assert.IsTrue(renderedslides.ContainsKey(t), "Rendered slides does not contain slides for the post script guy!");
                var slides = renderedslides[t];
                Assert.IsTrue(slides.Count == 0, "Wrong number of slides in the rendering");
                Utilities.Logger.ResetTestLogging();

                TextReader rdr = log.OpenText();
                string line = rdr.ReadLine();
                Assert.IsTrue(line.Contains("BadFileType"), "Error message for bad talk was not printed out");
            }
            finally
            {
                Utilities.Logger.ResetTestLogging();
            }
        }

#if false
        /// The pdf file here is much too large -- 180 megs -- to be put up in svn on code talk, unfortunately.
        [TestMethod]
        public void RenderGSCrashingTalk()
        {
            /// Make sure we don't hang during the test if we are rendering a talk that GS crashes on.
            /// I.e. don't pop a crash dialog when this happens!
            Talk t = TalkFromLocalFile("..\\..\\..\\t_DTBuilderLib\\Talk-badgs.pdf");

            Meeting m = MeetingFromSingleTalk(t);

            FileInfo log = new FileInfo("log-rendergscrashing.txt");
            if (log.Exists)
            {
                log.Delete();
            }
            try
            {
                Utilities.Logger.UseFileLogger(log);
                JPEGRender r = new JPEGRender();
                var renderedslides = r.RenderMeeting(m);
                Assert.IsTrue(renderedslides.ContainsKey(t), "Rendered slides does not contain slides for the bad PDF guy!");
                var slides = renderedslides[t];
                Assert.IsTrue(slides.Count == 1, "Should have one slide in the rendering!");
                Utilities.Logger.ResetTestLogging();

                TextReader rdr = log.OpenText();
                string line = rdr.ReadLine();
                Assert.IsTrue(line.Contains("GSFail"), "Error message for bad talk was not printed out");
            }
            finally
            {
                Utilities.Logger.ResetTestLogging();
            }
        }
#endif

        /// <summary>
        /// Given a local file, build a talk around it.
        /// </summary>
        /// <param name="localfile"></param>
        /// <returns></returns>
        private static Talk TalkFromLocalFile(string localfile)
        {
            return TalkFromLocalFile(localfile, "");
        }

        /// <summary>
        /// Generate a talk from a single file, but rename it slightly by prepending.
        /// </summary>
        /// <param name="p"></param>
        /// <param name="p_2"></param>
        /// <returns></returns>
        private static Talk TalkFromLocalFile(string localfile, string prefix)
        {
            Talk t = new Talk() { ID = "5", StartDate = DateTime.Now, EndDate = DateTime.Now, Title = "Dude!" };
            FileInfo ftest = new FileInfo(localfile);
            FileInfo f = new FileInfo(prefix + ftest.Name);
            ftest.CopyTo(f.FullName);

            t.SlideURL = f.FullName;
            return t;
        }

        /// <summary>
        /// Given a single talk, build a meeting around it.
        /// </summary>
        /// <param name="t"></param>
        /// <returns></returns>
        private static Meeting MeetingFromTalks(Talk[] t)
        {
            Session s = new Session() { StartDate = DateTime.Now, ID = "5", EndDate = DateTime.Now, Title = "Bogus" };
            s.Talks = t;

            Meeting m = new Meeting() { Title = "no way", Sessions = new Session[] { s }, ID = "5", StartDate = DateTime.Now, EndDate = DateTime.Now };
            return m;
        }

        /// <summary>
        /// Create a meeting from a single talk.
        /// </summary>
        /// <param name="t"></param>
        /// <returns></returns>
        private static Meeting MeetingFromSingleTalk(Talk t)
        {
            return MeetingFromTalks(new Talk[] { t });
        }
    }
}
